home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / vidhrdw / stactics.c < prev    next >
C/C++ Source or Header  |  2000-04-04  |  29KB  |  921 lines

  1. /***************************************************************************
  2.  
  3.   vidhrdw.c
  4.  
  5.   Functions to emulate the video hardware of the machine.
  6.  
  7. ---
  8.  
  9. The Video system used in Space Tactics is unusual.
  10. Here are my notes on how the video system works:
  11.  
  12. There are 4, 4K pages of Video RAM. (B,D,E & F)
  13.  
  14. The first 1K of each VRAM page contains the following:
  15. 0 0 V V V V V H H H H H   offset value for each 8x8 bitmap
  16.      (v-tile)  (h-tile)
  17.  
  18. The offset values are used to generate an access into the
  19. last 2K of the VRAM page:
  20. 1 D D D D D D D D V V V   here we find 8x8 character data
  21.      (offset)    (line)
  22.  
  23. In addition, in Page B, the upper nibble of the offset is
  24. also used to select the color palette for the tile.
  25.  
  26. Page B, D, E, and F all work similarly, except that pages
  27. D, E, and F can be offset from Page B by a given
  28. number of scanlines, based on the contents of the offset
  29. RAM
  30.  
  31. The offset RAM is addressed in this format:
  32. 1 0 0 0 P P P V V V V V V V V V
  33.         (Page)   (scanline)
  34. Page 4=D, 5=E, 6=F
  35.  
  36. Page D, E, and F are drawn offset from the top of the screen,
  37. starting on the first scanline which contains a 1 in the
  38. appropriate memory location
  39.  
  40. ---
  41.  
  42. The composited monitor image is seen in a mirror.  It appears
  43. to move when the player moves the handle, due to motors which
  44. tilt the mirror up and down, and the monitor left and right.
  45.  
  46. ---
  47.  
  48. As if this wasn't enough, there are also "3D" fire beams made
  49. of 120 green LED's which are on a mechanism in front of the mirror.
  50. Along with a single red "sight" LED.  I am reading in the sequence
  51. ROMS and building up a character set to simulate the LEDS with
  52. conventional character graphics.
  53.  
  54. Finally, there is a score display made of 7-segment LEDS, along
  55. with Credits, Barriers, and Rounds displays made of some other
  56. type of LED bar graphs.  I'm displaying them the best I can on the
  57. bottom line of the screen
  58.  
  59. ***************************************************************************/
  60.  
  61. #include "driver.h"
  62. #include "vidhrdw/generic.h"
  63.  
  64. /* These are defined in machine/stactics.c */
  65. extern int stactics_vert_pos;
  66. extern int stactics_horiz_pos;
  67. extern unsigned char *stactics_motor_on;
  68.  
  69. /* These are needed by machine/stactics.c  */
  70. int stactics_vblank_count;
  71. int stactics_shot_standby;
  72. int stactics_shot_arrive;
  73.  
  74. /* These are needed by driver/stactics.c   */
  75. unsigned char *stactics_scroll_ram;
  76. unsigned char *stactics_videoram_b;
  77. unsigned char *stactics_chardata_b;
  78. unsigned char *stactics_videoram_d;
  79. unsigned char *stactics_chardata_d;
  80. unsigned char *stactics_videoram_e;
  81. unsigned char *stactics_chardata_e;
  82. unsigned char *stactics_videoram_f;
  83. unsigned char *stactics_chardata_f;
  84. unsigned char *stactics_display_buffer;
  85.  
  86. static unsigned char *dirty_videoram_b;
  87. static unsigned char *dirty_chardata_b;
  88. static unsigned char *dirty_videoram_d;
  89. static unsigned char *dirty_chardata_d;
  90. static unsigned char *dirty_videoram_e;
  91. static unsigned char *dirty_chardata_e;
  92. static unsigned char *dirty_videoram_f;
  93. static unsigned char *dirty_chardata_f;
  94.  
  95. static int d_offset;
  96. static int e_offset;
  97. static int f_offset;
  98.  
  99. static int palette_select;
  100.  
  101. static struct osd_bitmap *tmpbitmap2;
  102. static struct osd_bitmap *bitmap_B;
  103. static struct osd_bitmap *bitmap_D;
  104. static struct osd_bitmap *bitmap_E;
  105. static struct osd_bitmap *bitmap_F;
  106.  
  107. static unsigned char *beamdata;
  108. static int states_per_frame;
  109.  
  110. #define DIRTY_CHARDATA_SIZE  0x100
  111. #define BEAMDATA_SIZE        0x800
  112.  
  113. /* The first 16 came from the 7448 BCD to 7-segment decoder data sheet */
  114. /* The rest are made up */
  115.  
  116. static unsigned char stactics_special_chars[32*8] = {
  117.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Space */
  118.     0x80, 0x80, 0x80, 0xf0, 0x80, 0x80, 0xf0, 0x00,   /* extras... */
  119.     0xf0, 0x80, 0x80, 0xf0, 0x00, 0x00, 0xf0, 0x00,   /* extras... */
  120.     0x90, 0x90, 0x90, 0xf0, 0x00, 0x00, 0x00, 0x00,   /* extras... */
  121.     0x00, 0x00, 0x00, 0xf0, 0x10, 0x10, 0xf0, 0x00,   /* extras... */
  122.     0x00, 0x00, 0x00, 0xf0, 0x80, 0x80, 0xf0, 0x00,   /* extras... */
  123.     0xf0, 0x90, 0x90, 0xf0, 0x10, 0x10, 0xf0, 0x00,   /* 9 */
  124.     0xf0, 0x90, 0x90, 0xf0, 0x90, 0x90, 0xf0, 0x00,   /* 8 */
  125.     0xf0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,   /* 7 */
  126.     0xf0, 0x80, 0x80, 0xf0, 0x90, 0x90, 0xf0, 0x00,   /* 6 */
  127.     0xf0, 0x80, 0x80, 0xf0, 0x10, 0x10, 0xf0, 0x00,   /* 5 */
  128.     0x90, 0x90, 0x90, 0xf0, 0x10, 0x10, 0x10, 0x00,   /* 4 */
  129.     0xf0, 0x10, 0x10, 0xf0, 0x10, 0x10, 0xf0, 0x00,   /* 3 */
  130.     0xf0, 0x10, 0x10, 0xf0, 0x80, 0x80, 0xf0, 0x00,   /* 2 */
  131.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,   /* 1 */
  132.     0xf0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xf0, 0x00,   /* 0 */
  133.  
  134.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Space */
  135.     0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* 1 pip */
  136.     0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00,   /* S for Score */
  137.     0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,   /* 2 pips */
  138.     0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,   /* 3 pips */
  139.     0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00,   /* C for Credits */
  140.     0xe0, 0x90, 0x90, 0xe0, 0x90, 0x90, 0xe0, 0x00,   /* B for Barriers */
  141.     0xe0, 0x90, 0x90, 0xe0, 0xc0, 0xa0, 0x90, 0x00,   /* R for Rounds */
  142.     0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,   /* 4 pips */
  143.     0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00, 0x00,   /* Colon */
  144.     0x40, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Sight */
  145.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Space (Unused) */
  146.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Space (Unused) */
  147.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Space (Unused) */
  148.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* Space (Unused) */
  149.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00    /* Space */
  150. };
  151.  
  152.  
  153. static int firebeam_state;
  154. static int old_firebeam_state;
  155.  
  156. void stactics_vh_convert_color_prom(unsigned char *palette,
  157.                                     unsigned short *colortable,
  158.                                     const unsigned char *color_prom)
  159. {
  160.     int i,j;
  161.  
  162.     #define TOTAL_COLORS(gfxn) (Machine->gfx[gfxn]->total_colors * Machine->gfx[gfxn]->color_granularity)
  163.     #define COLOR(gfxn,offs) (colortable[Machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs*sizeof(unsigned short)])
  164.  
  165.     /* Now make the palette */
  166.  
  167.     for (i=0;i<16;i++)
  168.     {
  169.         int bit0,bit1,bit2, bit3;
  170.  
  171.         bit0 = i & 1;
  172.         bit1 = (i >> 1) & 1;
  173.         bit2 = (i >> 2) & 1;
  174.         bit3 = (i >> 3) & 1;
  175.  
  176.         /* red component */
  177.         *(palette++) = 0xff * bit0;
  178.  
  179.         /* green component */
  180.         *(palette++) = 0xff * bit1 - 0xcc * bit3;
  181.  
  182.         /* blue component */
  183.         *(palette++) = 0xff * bit2;
  184.     }
  185.  
  186.     /* The color prom in Space Tactics is used for both   */
  187.     /* color codes, and priority layering of the 4 layers */
  188.  
  189.     /* Since we are taking care of the layering by our    */
  190.     /* drawing order, we don't need all of the color prom */
  191.     /* entries */
  192.  
  193.     /* For each of 4 color schemes */
  194.     for(i=0;i<4;i++)
  195.     {
  196.         /* For page B - Alphanumerics and alien shots */
  197.         for(j=0;j<16;j++)
  198.         {
  199.             *(colortable++) = 0;
  200.             *(colortable++) = color_prom[i*0x100+0x01*0x10+j];
  201.         }
  202.         /* For page F - Close Aliens (these are all the same color) */
  203.         for(j=0;j<16;j++)
  204.         {
  205.             *(colortable++) = 0;
  206.             *(colortable++) = color_prom[i*0x100+0x02*0x10];
  207.         }
  208.         /* For page E - Medium Aliens (these are all the same color) */
  209.         for(j=0;j<16;j++)
  210.         {
  211.             *(colortable++) = 0;
  212.             *(colortable++) = color_prom[i*0x100+0x04*0x10+j];
  213.         }
  214.         /* For page D - Far Aliens (these are all the same color) */
  215.         for(j=0;j<16;j++)
  216.         {
  217.             *(colortable++) = 0;
  218.             *(colortable++) = color_prom[i*0x100+0x08*0x10+j];
  219.         }
  220.     }
  221. }
  222.  
  223. /***************************************************************************
  224.  
  225.   Start the video hardware emulation.
  226.  
  227. ***************************************************************************/
  228.  
  229. int stactics_vh_start(void)
  230. {
  231.     int i,j;
  232.     const unsigned char *firebeam_data;
  233.     unsigned char firechar[256*8*9];
  234.  
  235.     if ((tmpbitmap  = osd_create_bitmap(Machine->drv->screen_width,Machine->drv->screen_height)) == 0) return 1;
  236.     if ((tmpbitmap2 = osd_create_bitmap(Machine->drv->screen_width,Machine->drv->screen_height)) == 0) return 1;
  237.     if ((bitmap_B = osd_create_bitmap(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)   return 1;
  238.     if ((bitmap_D = osd_create_bitmap(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)   return 1;
  239.     if ((bitmap_E = osd_create_bitmap(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)   return 1;
  240.     if ((bitmap_F = osd_create_bitmap(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)   return 1;
  241.  
  242.     /* Allocate dirty buffers */
  243.     if ((dirty_videoram_b = (unsigned char *)malloc(videoram_size)) == 0)       return 1;
  244.     if ((dirty_videoram_d = (unsigned char *)malloc(videoram_size)) == 0)       return 1;
  245.     if ((dirty_videoram_e = (unsigned char *)malloc(videoram_size)) == 0)       return 1;
  246.     if ((dirty_videoram_f = (unsigned char *)malloc(videoram_size)) == 0)       return 1;
  247.     if ((dirty_chardata_b = (unsigned char *)malloc(DIRTY_CHARDATA_SIZE)) == 0) return 1;
  248.     if ((dirty_chardata_d = (unsigned char *)malloc(DIRTY_CHARDATA_SIZE)) == 0) return 1;
  249.     if ((dirty_chardata_e = (unsigned char *)malloc(DIRTY_CHARDATA_SIZE)) == 0) return 1;
  250.     if ((dirty_chardata_f = (unsigned char *)malloc(DIRTY_CHARDATA_SIZE)) == 0) return 1;
  251.  
  252.     memset(dirty_videoram_b,1,videoram_size);
  253.     memset(dirty_videoram_d,1,videoram_size);
  254.     memset(dirty_videoram_e,1,videoram_size);
  255.     memset(dirty_videoram_f,1,videoram_size);
  256.     memset(dirty_chardata_b,1,DIRTY_CHARDATA_SIZE);
  257.     memset(dirty_chardata_d,1,DIRTY_CHARDATA_SIZE);
  258.     memset(dirty_chardata_e,1,DIRTY_CHARDATA_SIZE);
  259.     memset(dirty_chardata_f,1,DIRTY_CHARDATA_SIZE);
  260.  
  261.     d_offset = 0;
  262.     e_offset = 0;
  263.     f_offset = 0;
  264.  
  265.     palette_select = 0;
  266.     stactics_vblank_count = 0;
  267.     stactics_shot_standby = 1;
  268.     stactics_shot_arrive = 0;
  269.     firebeam_state = 0;
  270.     old_firebeam_state = 0;
  271.  
  272.     /* Create a fake character set for LED fire beam */
  273.  
  274.     memset(firechar,0,sizeof(firechar));
  275.     for(i=0;i<256;i++)
  276.     {
  277.         for(j=0;j<8;j++)
  278.         {
  279.             if ((i>>j)&0x01)
  280.             {
  281.                 firechar[i*9+(7-j)]   |= (0x01<<(7-j));
  282.                 firechar[i*9+(7-j)+1] |= (0x01<<(7-j));
  283.             }
  284.         }
  285.     }
  286.  
  287.     for(i=0;i<256;i++)
  288.     {
  289.         decodechar(Machine->gfx[4],
  290.                    i,
  291.                    firechar,
  292.                    Machine->drv->gfxdecodeinfo[4].gfxlayout);
  293.     }
  294.  
  295.     /* Decode the Fire Beam ROM for later      */
  296.     /* (I am basically just juggling the bytes */
  297.     /* and storing it again to make it easier) */
  298.  
  299.     if ((beamdata = (unsigned char *)malloc(BEAMDATA_SIZE)) == 0) return 1;
  300.  
  301.     firebeam_data = memory_region(REGION_GFX1);
  302.  
  303.     for(i=0;i<256;i++)
  304.     {
  305.         beamdata[i*8]   = firebeam_data[i                   ];
  306.         beamdata[i*8+1] = firebeam_data[i + 1024            ];
  307.         beamdata[i*8+2] = firebeam_data[i              + 256];
  308.         beamdata[i*8+3] = firebeam_data[i + 1024       + 256];
  309.         beamdata[i*8+4] = firebeam_data[i        + 512      ];
  310.         beamdata[i*8+5] = firebeam_data[i + 1024 + 512      ];
  311.         beamdata[i*8+6] = firebeam_data[i        + 512 + 256];
  312.         beamdata[i*8+7] = firebeam_data[i + 1024 + 512 + 256];
  313.     }
  314.  
  315.     /* Build some characters for simulating the LED displays */
  316.  
  317.     for(i=0;i<32;i++)
  318.     {
  319.         decodechar(Machine->gfx[5],
  320.                    i,
  321.                    stactics_special_chars,
  322.                    Machine->drv->gfxdecodeinfo[5].gfxlayout);
  323.     }
  324.  
  325.     stactics_vblank_count = 0;
  326.     stactics_vert_pos = 0;
  327.     stactics_horiz_pos = 0;
  328.     *stactics_motor_on = 0;
  329.  
  330.     return 0;
  331. }
  332.  
  333.  
  334. /***************************************************************************
  335.  
  336.   Stop the video hardware emulation.
  337.  
  338. ***************************************************************************/
  339. void stactics_vh_stop(void)
  340. {
  341.     free(dirty_videoram_b);
  342.     free(dirty_videoram_d);
  343.     free(dirty_videoram_e);
  344.     free(dirty_videoram_f);
  345.     free(dirty_chardata_b);
  346.     free(dirty_chardata_d);
  347.     free(dirty_chardata_e);
  348.     free(dirty_chardata_f);
  349.  
  350.     free(beamdata);
  351.  
  352.     osd_free_bitmap(tmpbitmap);
  353.     osd_free_bitmap(tmpbitmap2);
  354.     osd_free_bitmap(bitmap_B);
  355.     osd_free_bitmap(bitmap_D);
  356.     osd_free_bitmap(bitmap_E);
  357.     osd_free_bitmap(bitmap_F);
  358. }
  359.  
  360.  
  361. WRITE_HANDLER( stactics_palette_w )
  362. {
  363.     int old_palette_select = palette_select;
  364.  
  365.     switch (offset)
  366.     {
  367.         case 0:
  368.             palette_select = (palette_select & 0x02) | (data&0x01);
  369.             break;
  370.         case 1:
  371.             palette_select = (palette_select & 0x01) | ((data&0x01)<<1);
  372.             break;
  373.         default:
  374.             return;
  375.     }
  376.  
  377.     if (old_palette_select != palette_select)
  378.     {
  379.         memset(dirty_videoram_b,1,videoram_size);
  380.         memset(dirty_videoram_d,1,videoram_size);
  381.         memset(dirty_videoram_e,1,videoram_size);
  382.         memset(dirty_videoram_f,1,videoram_size);
  383.     }
  384.     return;
  385. }
  386.  
  387.  
  388. WRITE_HANDLER( stactics_scroll_ram_w )
  389. {
  390.     int temp;
  391.  
  392.     if (stactics_scroll_ram[offset] != data)
  393.     {
  394.         stactics_scroll_ram[offset] = data;
  395.         temp = (offset&0x700)>>8;
  396.         switch(temp)
  397.         {
  398.             case 4:  // Page D
  399.             {
  400.                 if (data&0x01)
  401.                     d_offset = offset&0xff;
  402.                 break;
  403.             }
  404.             case 5:  // Page E
  405.             {
  406.                 if (data&0x01)
  407.                     e_offset = offset&0xff;
  408.                 break;
  409.             }
  410.             case 6:  // Page F
  411.             {
  412.                 if (data&0x01)
  413.                     f_offset = offset&0xff;
  414.                 break;
  415.             }
  416.         }
  417.     }
  418. }
  419.  
  420. WRITE_HANDLER( stactics_speed_latch_w )
  421. {
  422.     /* This writes to a shift register which is clocked by   */
  423.     /* a 555 oscillator.  This value determines the speed of */
  424.     /* the LED fire beams as follows:                        */
  425.  
  426.     /*   555_freq / bits_in_SR * edges_in_SR / states_in_PR67 / frame_rate */
  427.     /*      = num_led_states_per_frame  */
  428.     /*   36439 / 8 * x / 32 / 60 ~= 19/8*x */
  429.  
  430.     /* Here, we will count the number of rising edges in the shift register */
  431.  
  432.     int i;
  433.     int num_rising_edges = 0;
  434.  
  435.     for(i=0;i<8;i++)
  436.     {
  437.         if ( (((data>>i)&0x01) == 1) && (((data>>((i+1)%8))&0x01) == 0))
  438.             num_rising_edges++;
  439.     }
  440.  
  441.     states_per_frame = num_rising_edges*19/8;
  442. }
  443.  
  444. WRITE_HANDLER( stactics_shot_trigger_w )
  445. {
  446.     stactics_shot_standby = 0;
  447. }
  448.  
  449. WRITE_HANDLER( stactics_shot_flag_clear_w )
  450. {
  451.     stactics_shot_arrive = 0;
  452. }
  453.  
  454. WRITE_HANDLER( stactics_videoram_b_w )
  455. {
  456.     if (stactics_videoram_b[offset] != data)
  457.     {
  458.         stactics_videoram_b[offset] = data;
  459.         dirty_videoram_b[offset] = 1;
  460.     }
  461. }
  462.  
  463. WRITE_HANDLER( stactics_chardata_b_w )
  464. {
  465.     if (stactics_chardata_b[offset] != data)
  466.     {
  467.         stactics_chardata_b[offset] = data;
  468.         dirty_chardata_b[offset>>3] = 1;
  469.     }
  470. }
  471.  
  472. WRITE_HANDLER( stactics_videoram_d_w )
  473. {
  474.     if (stactics_videoram_d[offset] != data)
  475.     {
  476.         stactics_videoram_d[offset] = data;
  477.         dirty_videoram_d[offset] = 1;
  478.     }
  479. }
  480.  
  481. WRITE_HANDLER( stactics_chardata_d_w )
  482. {
  483.     if (stactics_chardata_d[offset] != data)
  484.     {
  485.         stactics_chardata_d[offset] = data;
  486.         dirty_chardata_d[offset>>3] = 1;
  487.     }
  488. }
  489.  
  490. WRITE_HANDLER( stactics_videoram_e_w )
  491. {
  492.     if (stactics_videoram_e[offset] != data)
  493.     {
  494.         stactics_videoram_e[offset] = data;
  495.         dirty_videoram_e[offset] = 1;
  496.     }
  497. }
  498.  
  499. WRITE_HANDLER( stactics_chardata_e_w )
  500. {
  501.     if (stactics_chardata_e[offset] != data)
  502.     {
  503.         stactics_chardata_e[offset] = data;
  504.         dirty_chardata_e[offset>>3] = 1;
  505.     }
  506. }
  507.  
  508. WRITE_HANDLER( stactics_videoram_f_w )
  509. {
  510.     if (stactics_videoram_f[offset] != data)
  511.     {
  512.         stactics_videoram_f[offset] = data;
  513.         dirty_videoram_f[offset] = 1;
  514.     }
  515. }
  516.  
  517. WRITE_HANDLER( stactics_chardata_f_w )
  518. {
  519.     if (stactics_chardata_f[offset] != data)
  520.     {
  521.         stactics_chardata_f[offset] = data;
  522.         dirty_chardata_f[offset>>3] = 1;
  523.     }
  524. }
  525.  
  526. /* Actual area for visible monitor stuff is only 30*8 lines */
  527. /* The rest is used for the score, etc. */
  528.  
  529. static const struct rectangle visible_screen_area = {0*8, 32*8, 0*8, 30*8};
  530.  
  531. /***************************************************************************
  532.  
  533.   Draw the game screen in the given osd_bitmap.
  534.   Do NOT call osd_update_display() from this function, it will be called by
  535.   the main emulation engine.
  536.  
  537. ***************************************************************************/
  538.  
  539. void stactics_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
  540. {
  541.     int offs, sx, sy, i;
  542.     int char_number;
  543.     int color_code;
  544.     int pixel_x, pixel_y;
  545.  
  546.     int palette_offset = palette_select * 64;
  547.  
  548.     for(offs=0x400-1; offs>=0; offs--)
  549.     {
  550.         sx = offs%32;
  551.         sy = offs/32;
  552.  
  553.         color_code = palette_offset + (stactics_videoram_b[offs]>>4);
  554.  
  555.         /* Draw aliens in Page D */
  556.  
  557.         char_number = stactics_videoram_d[offs];
  558.  
  559.         if (dirty_chardata_d[char_number] == 1)
  560.         {
  561.             decodechar(Machine->gfx[3],
  562.                        char_number,
  563.                        stactics_chardata_d,
  564.                        Machine->drv->gfxdecodeinfo[3].gfxlayout);
  565.             dirty_chardata_d[char_number] = 2;
  566.             dirty_videoram_d[offs] = 1;
  567.         }
  568.         else if (dirty_chardata_d[char_number] == 2)
  569.         {
  570.             dirty_videoram_d[offs] = 1;
  571.         }
  572.  
  573.         if (dirty_videoram_d[offs])
  574.         {
  575.             drawgfx(bitmap_D,Machine->gfx[3],
  576.                     char_number,
  577.                     color_code,
  578.                     0,0,
  579.                     sx*8,sy*8,
  580.                     &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  581.             dirty_videoram_d[offs] = 0;
  582.         }
  583.  
  584.         /* Draw aliens in Page E */
  585.  
  586.         char_number = stactics_videoram_e[offs];
  587.  
  588.         if (dirty_chardata_e[char_number] == 1)
  589.         {
  590.             decodechar(Machine->gfx[2],
  591.                        char_number,
  592.                        stactics_chardata_e,
  593.                        Machine->drv->gfxdecodeinfo[2].gfxlayout);
  594.             dirty_chardata_e[char_number] = 2;
  595.             dirty_videoram_e[offs] = 1;
  596.         }
  597.         else if (dirty_chardata_e[char_number] == 2)
  598.         {
  599.             dirty_videoram_e[offs] = 1;
  600.         }
  601.  
  602.         if (dirty_videoram_e[offs])
  603.         {
  604.             drawgfx(bitmap_E,Machine->gfx[2],
  605.                     char_number,
  606.                     color_code,
  607.                     0,0,
  608.                     sx*8,sy*8,
  609.                     &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  610.             dirty_videoram_e[offs] = 0;
  611.         }
  612.  
  613.         /* Draw aliens in Page F */
  614.  
  615.         char_number = stactics_videoram_f[offs];
  616.  
  617.         if (dirty_chardata_f[char_number] == 1)
  618.         {
  619.             decodechar(Machine->gfx[1],
  620.                        char_number,
  621.                        stactics_chardata_f,
  622.                        Machine->drv->gfxdecodeinfo[1].gfxlayout);
  623.             dirty_chardata_f[char_number] = 2;
  624.             dirty_videoram_f[offs] = 1;
  625.         }
  626.         else if (dirty_chardata_f[char_number] == 2)
  627.         {
  628.             dirty_videoram_f[offs] = 1;
  629.         }
  630.  
  631.         if (dirty_videoram_f[offs])
  632.         {
  633.             drawgfx(bitmap_F,Machine->gfx[1],
  634.                     char_number,
  635.                     color_code,
  636.                     0,0,
  637.                     sx*8,sy*8,
  638.                     &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  639.             dirty_videoram_f[offs] = 0;
  640.         }
  641.  
  642.         /* Draw the page B stuff */
  643.  
  644.         char_number = stactics_videoram_b[offs];
  645.  
  646.         if (dirty_chardata_b[char_number] == 1)
  647.         {
  648.             decodechar(Machine->gfx[0],
  649.                        char_number,
  650.                        stactics_chardata_b,
  651.                        Machine->drv->gfxdecodeinfo[0].gfxlayout);
  652.             dirty_chardata_b[char_number] = 2;
  653.             dirty_videoram_b[offs] = 1;
  654.         }
  655.         else if (dirty_chardata_b[char_number] == 2)
  656.         {
  657.             dirty_videoram_b[offs] = 1;
  658.         }
  659.  
  660.         if (dirty_videoram_b[offs])
  661.         {
  662.             drawgfx(bitmap_B,Machine->gfx[0],
  663.                     char_number,
  664.                     color_code,
  665.                     0,0,
  666.                     sx*8,sy*8,
  667.                     &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  668.             dirty_videoram_b[offs] = 0;
  669.         }
  670.  
  671.     }
  672.  
  673.     /* Now, composite the four layers together */
  674.  
  675.     copyscrollbitmap(tmpbitmap2,bitmap_D,0,0,1,&d_offset,
  676.                      &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  677.     copyscrollbitmap(tmpbitmap2,bitmap_E,0,0,1,&e_offset,
  678.                      &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  679.     copyscrollbitmap(tmpbitmap2,bitmap_F,0,0,1,&f_offset,
  680.                      &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  681.     copybitmap(tmpbitmap2,bitmap_B,0,0,0,0,
  682.                      &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  683.  
  684.     /* Now flip X & simulate the monitor motion */
  685.     fillbitmap(bitmap, Machine->pens[0], &Machine->drv->visible_area);
  686.     copybitmap(bitmap,tmpbitmap2,1,0,stactics_horiz_pos,stactics_vert_pos,
  687.                 &visible_screen_area,TRANSPARENCY_NONE,0);
  688.  
  689.     /* Finally, draw stuff that is on the console or on top of the monitor (LED's) */
  690.  
  691.     /***** Draw Score Display *****/
  692.  
  693.     pixel_x = 16;
  694.     pixel_y = 248;
  695.  
  696.     /* Draw an S */
  697.     drawgfx(bitmap,Machine->gfx[5],
  698.             18,
  699.             0,
  700.             0,0,
  701.             pixel_x,pixel_y,
  702.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  703.     pixel_x+=6;
  704.     /* Draw a colon */
  705.     drawgfx(bitmap,Machine->gfx[5],
  706.             25,
  707.             0,
  708.             0,0,
  709.             pixel_x,pixel_y,
  710.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  711.     pixel_x+=6;
  712.     /* Draw the digits */
  713.     for(i=1;i<7;i++)
  714.     {
  715.         drawgfx(bitmap,Machine->gfx[5],
  716.                 stactics_display_buffer[i]&0x0f,
  717.                 16,
  718.                 0,0,
  719.                 pixel_x,pixel_y,
  720.                 &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  721.         pixel_x+=6;
  722.     }
  723.  
  724.     /***** Draw Credits Indicator *****/
  725.  
  726.     pixel_x = 64+16;
  727.  
  728.     /* Draw a C */
  729.     drawgfx(bitmap,Machine->gfx[5],
  730.             21,
  731.             0,
  732.             0,0,
  733.             pixel_x,pixel_y,
  734.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  735.     pixel_x+=6;
  736.     /* Draw a colon */
  737.     drawgfx(bitmap,Machine->gfx[5],
  738.             25,
  739.             0,
  740.             0,0,
  741.             pixel_x,pixel_y,
  742.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  743.     pixel_x+=6;
  744.     /* Draw the pips */
  745.     for(i=7;i<9;i++)
  746.     {
  747.         drawgfx(bitmap,Machine->gfx[5],
  748.                 16 + (~stactics_display_buffer[i]&0x0f),
  749.                 16,
  750.                 0,0,
  751.                 pixel_x,pixel_y,
  752.                 &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  753.         pixel_x+=2;
  754.     }
  755.  
  756.     /***** Draw Rounds Indicator *****/
  757.  
  758.     pixel_x = 128+16;
  759.  
  760.     /* Draw an R */
  761.     drawgfx(bitmap,Machine->gfx[5],
  762.             22,
  763.             0,
  764.             0,0,
  765.             pixel_x,pixel_y,
  766.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  767.     pixel_x+=6;
  768.     /* Draw a colon */
  769.     drawgfx(bitmap,Machine->gfx[5],
  770.             25,
  771.             0,
  772.             0,0,
  773.             pixel_x,pixel_y,
  774.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  775.     pixel_x+=6;
  776.     /* Draw the pips */
  777.     for(i=9;i<12;i++)
  778.     {
  779.         drawgfx(bitmap,Machine->gfx[5],
  780.                 16 + (~stactics_display_buffer[i]&0x0f),
  781.                 16,
  782.                 0,0,
  783.                 pixel_x,pixel_y,
  784.                 &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  785.         pixel_x+=2;
  786.     }
  787.  
  788.     /***** Draw Barriers Indicator *****/
  789.  
  790.     pixel_x = 192+16;
  791.     /* Draw a B */
  792.     drawgfx(bitmap,Machine->gfx[5],
  793.             23,
  794.             0,
  795.             0,0,
  796.             pixel_x,pixel_y,
  797.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  798.     pixel_x+=6;
  799.     /* Draw a colon */
  800.     drawgfx(bitmap,Machine->gfx[5],
  801.             25,
  802.             0,
  803.             0,0,
  804.             pixel_x,pixel_y,
  805.             &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  806.     pixel_x+=6;
  807.     /* Draw the pips */
  808.     for(i=12;i<16;i++)
  809.     {
  810.         drawgfx(bitmap,Machine->gfx[5],
  811.                 16 + (~stactics_display_buffer[i]&0x0f),
  812.                 16,
  813.                 0,0,
  814.                 pixel_x,pixel_y,
  815.                 &Machine->drv->visible_area,TRANSPARENCY_NONE,0);
  816.         pixel_x+=2;
  817.     }
  818.  
  819.     /* An LED fire beam! */
  820.     /* (There were 120 green LEDS mounted in the cabinet in the game, */
  821.     /*  and one red one, for the sight)                               */
  822.  
  823.     /* First, update the firebeam state */
  824.  
  825.     old_firebeam_state = firebeam_state;
  826.     if (stactics_shot_standby == 0)
  827.     {
  828.         firebeam_state = (firebeam_state + states_per_frame)%512;
  829.     }
  830.  
  831.     /* These are thresholds for the two shots from the LED fire ROM */
  832.     /* (Note: There are two more for sound triggers, */
  833.     /*        whenever that gets implemented)        */
  834.  
  835.     if ((old_firebeam_state < 0x8b) & (firebeam_state >= 0x8b))
  836.         stactics_shot_arrive = 1;
  837.  
  838.     if ((old_firebeam_state < 0xca) & (firebeam_state >= 0xca))
  839.         stactics_shot_arrive = 1;
  840.  
  841.     if (firebeam_state > 255)
  842.     {
  843.         firebeam_state = 0;
  844.         stactics_shot_standby = 1;
  845.     }
  846.  
  847.     /* Now, draw the beam */
  848.  
  849.     pixel_x = 15;
  850.     pixel_y = 166;
  851.  
  852.     for(i=0;i<8;i++)
  853.     {
  854.         if ((i%2)==1)
  855.         {
  856.             /* Draw 7 LEDS on each side */
  857.             drawgfx(bitmap,Machine->gfx[4],
  858.                     beamdata[firebeam_state*8+i]&0x7f,
  859.                     16*2,  /* Make it green */
  860.                     0,0,
  861.                     pixel_x,pixel_y,
  862.                     &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  863.             drawgfx(bitmap,Machine->gfx[4],
  864.                     beamdata[firebeam_state*8+i]&0x7f,
  865.                     16*2,  /* Make it green */
  866.                     1,0,
  867.                     255-pixel_x,pixel_y,
  868.                     &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  869.             pixel_x+=14;
  870.             pixel_y-=7;
  871.         }
  872.         else
  873.         {
  874.             /* Draw 8 LEDS on each side */
  875.             drawgfx(bitmap,Machine->gfx[4],
  876.                     beamdata[firebeam_state*8+i],
  877.                     16*2,  /* Make it green */
  878.                     0,0,
  879.                     pixel_x,pixel_y,
  880.                     &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  881.             drawgfx(bitmap,Machine->gfx[4],
  882.                     beamdata[firebeam_state*8+i],
  883.                     16*2,  /* Make it green */
  884.                     1,0,
  885.                     255-pixel_x,pixel_y,
  886.                     &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  887.             pixel_x+=16;
  888.             pixel_y-=8;
  889.         }
  890.  
  891.     }
  892.  
  893.     /* Red Sight LED */
  894.  
  895.     pixel_x = 134;
  896.     pixel_y = 112;
  897.  
  898.     if (*stactics_motor_on & 0x01)
  899.     {
  900.         drawgfx(bitmap,Machine->gfx[5],
  901.                 26,
  902.                 16, /* red */
  903.                 0,0,
  904.                 pixel_x,pixel_y,
  905.                 &Machine->drv->visible_area,TRANSPARENCY_COLOR,0);
  906.     }
  907.  
  908.     /* Update vblank counter */
  909.     stactics_vblank_count++;
  910.  
  911.     /* reset dirty flags */
  912.     for(i=0;i<0xff;i++)
  913.     {
  914.         dirty_chardata_b[i] &= 0x01;
  915.         dirty_chardata_d[i] &= 0x01;
  916.         dirty_chardata_e[i] &= 0x01;
  917.         dirty_chardata_f[i] &= 0x01;
  918.     }
  919.  
  920. }
  921.